/* Autore: Nicola Agosti */
/*
Data una matrice di dimensione uguale a 10 righe per 10 colonne contenente elementi generati in modo
casuale nell'intervallo [-99; 99].
Scrivere un programma in linguaggio C che cacloli la media degli elementi:
 - di ogni riga;
 - di ogni colonna;
 - della diagonale principale;
 - della diagonale secondaria.
*/

#define _CRT_SECURE_NO_WARNINGS /* Necessario se utilizziamo Visual Studio */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define DIM 10

#define MAX_VAL 99
#define MIN_VAL -99

int main()
{
	/*
	Per dichiarare una matrice (vettore bidimensionale) devo indicare tra parentesi quadre le sue dimensioni,
	ad esempio: int matrice[numero_di_righe][numero_di_colonne]

	Se il numero di righe è uguale a quello delle colonne si dice che la matrice è quadrata.
	*/
	int matrice[DIM][DIM], i, j;
	float mediaRiga[DIM], mediaColonna[DIM], mediaDiagPrinc = 0, mediaDiagSecond = 0;

	/* Inizializzo la generazione dei numeri casuali */
	srand(time(NULL));

	/* Inizializzo a zero gli elementi dei vettori "mediaRiga" e "mediaColonna" */
	for (i = 0; i < DIM; i++)
	{
		mediaRiga[i] = 0;
		mediaColonna[i] = 0;
	}

	/* Scorro tutti gli elementi della matrice e salvo in ognuono un nuovo numero intero generato casualmente */
	/* 
	Il ciclo for più esterno scandisce le righe (il primo indice della matrice), mentre il ciclo for più interno
	scorre tutte le celle (utilizzando il secondo indice della matrice che seleziona la colonna) della riga
	selezionata dal ciclo più esterno.
	
	CONSIGLIO: se possibile è meglio scandire la matrice per righe... la "memoria cache" lavora in modo più efficiente!
	*/
	for (i = 0; i < DIM; i++)
	{
		for (j = 0; j < DIM; j++)
		{
			/* La formula permette di generare un numero casuale limitato in un intervallo che non parte da zero */
			matrice[i][j] = rand() % (MAX_VAL - MIN_VAL + 1) + MIN_VAL;
		}
	}

	/* Calcolo la somma degli elementi di ogni riga e poi divido la somma per DIM */
	for (i = 0; i < DIM; i++)
	{
		for (j = 0; j < DIM; j++)
		{
			/* Sommo gli elementi della riga uno ad uno */
			mediaRiga[i] += matrice[i][j];
		}

		/* Ho finito di sommare gli elementi di una riga, ne calcolo la media */
		mediaRiga[i] /= DIM;
	}

	/* Calcolo la somma degli elementi di ogni colonna e poi divido la somma per DIM */
	/*
	Per scorrere la matrice per colonne basta "scambiare" il ciclo più interno con 
	quello più esterno in modo che prima venga selezionata la colonna e poi vengano
	selezionati gli elementi della colonna attraverso l'indice di riga
	*/
	for (j = 0; j < DIM; j++)
	{
		for (i = 0; i < DIM; i++)
		{
			/* Sommo gli elementi della colonna uno ad uno */
			mediaColonna[j] += matrice[i][j];
		}

		/* Ho finito di sommare gli elementi di una colonna, ne calcolo la media */
		mediaColonna[j] /= DIM;
	}

	/* Calcolo la somma degli elementi della diagonale principale e poi divido la somma per DIM */
	/*
	La diagonale principale esiste solo nelle matrici quadrate ed è composta dagli elementi che 
	appartengono alla diagonale del "quadrato" che parte dall'angolo in alto a sinistra e termina
	nell'angolo in basso a destra.

	Gli elementi della diagonale principale sono caratterizzati dall'avere l'indice di riga 
	uguale a quello di colonna.
	*/
	for (i = 0; i < DIM; i++)
	{
		/* Sommo gli elementi della diagonale principale uno ad uno */
		mediaDiagPrinc += matrice[i][i];
	}

	/* Ho finito di sommare gli elementi della diagonale principale, ne calcolo la media */
	mediaDiagPrinc /= DIM;

	/* Calcolo la somma degli elementi della diagonale secondaria e poi divido la somma per DIM */
	/*
	La diagonale secondaria esiste solo nelle matrici quadrate ed è composta dagli elementi che
	appartengono alla diagonale del "quadrato" che parte dall'angolo in alto a destra e termina
	nell'angolo in basso a sinistra.

	Gli elementi della diagonale secondaria sono caratterizzati dall'avere l'indice di colonna
	uguale all'indice di colonna massimo meno l'indice di riga, cioè:
	colonna = (DIM - 1) - riga;
	*/
	for (i = 0; i < DIM; i++)
	{
		/* Sommo gli elementi della diagonale secondaria uno ad uno */
		mediaDiagSecond += matrice[i][(DIM - 1) - i];
	}

	/* Ho finito di sommare gli elementi della diagonale secondaria, ne calcolo la media */
	mediaDiagSecond /= DIM;

	/*** ORA MI CONCENTRO SULL'OUTPUT ***/

	/* Stampo la media della diagonale secondaria opportunamente allineata */
	/* Prima stampo il titolo della tabella */
	printf("          MEDIA DELLE RIGHE, DELLE COLONNE E DELLE DIAGONALI          ");
	printf("| %6.2f\n", mediaDiagSecond);

	/* Stampo una riga di "-" per dividere gli elementi della matrice dalle medie delle colonne */
	for (i = 0; i < 7 * DIM + 8; i++)
	{
		printf("-");
	}
	printf("\n");

	/* Stampo gli elementi della matrice e le medie delle righe */
	for (i = 0; i < DIM; i++)
	{
		for (j = 0; j < DIM; j++)
		{
			/* Stampo gli elementi della riga uno ad uno */
			printf("%6d ", matrice[i][j]);
		}

		/* Ho finito di stampare gli elementi una riga, aggiungo la media e vado a capo */
		printf("| %6.2f\n", mediaRiga[i]);
	}

	/* Stampo una riga di "-" per dividere gli elementi della matrice dalle medie delle colonne */
	for (i = 0; i < 7 * DIM + 8; i++)
	{
		printf("-");
	}

	/* Stampo le medie delle colonne */
	printf("\n");
	for (i = 0; i < DIM; i++)
	{
		printf("%6.2f ", mediaColonna[i]);
	}

	/* Stampo la media della diagonale principale */
	printf("| %6.2f\n", mediaDiagPrinc);

	return 0;
}